package com.lpit.utils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class IDUtil {

    /*定义加密算法*/
    private static final String KEY = "AES";
    /*密钥*/
    private static final String KEY_SECART = "1234567890123456";

    /*数字加密*/
    public static String encyNumber(Long number) {
        /**
         * %d 表示将数字转换为十进制表示，%013d 表示将数字格式化为长度为 13 的字符串，不足 13 位的地方在前面添加 0
         * */
        return String.format("%d%013d", 0, number);
    }

    /*字符串加密*/
    public static String ency(String s) throws Exception {
        /*将加密密钥 KEY_SECRET 转换为字节数组 bytes*/
        byte[] bytes = KEY_SECART.getBytes();

        /*使用 SecretKeySpec 类创建一个密钥规范 secretKeySpec，将字节数组 bytes 和加密算法 KEY 作为参数*/
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, KEY);

        /*调用 Cipher.getInstance(KEY) 方法，使用加密算法 KEY 创建一个 Cipher 实例 instance*/
        Cipher instance = Cipher.getInstance(KEY);

        /*使用密钥规范 secretKeySpec 进行初始化，设置加密模式为加密模式*/
        instance.init(Cipher.ENCRYPT_MODE, secretKeySpec);

        /*进行加密操作，返回加密后的字节数组 bytes1*/
        byte[] bytes1 = instance.doFinal(s.getBytes());

        /*调用方法将加密后的字节数组转换为十六进制字符串表示*/
        return byte2hex(bytes1);
    }

    /*将字节数组转换为十六进制字符串表示*/
    public static String byte2hex(byte[] bytes) {
        /*定义StringBuilder*/
        StringBuilder hs = new StringBuilder();
        String stmp;

        for (byte aByte : bytes) {
            /*对每个字节将其转换为对应的两位十六进制字符串，并将结果保存在 stmp 变量中*/
            stmp = Integer.toHexString(aByte & 0XFF);
            /*如果长度为 1，说明转换得到的十六进制字符串只有一位，需要在前面补上 0，然后将结果追加到 hs 中*/
            if (stmp.length() == 1) {
                hs.append("0").append(stmp);
            } else {
                /*如果长度大于 1，直接将结果追加到 hs 中*/
                hs.append(stmp);
            }
        }

        /*将 hs 转换为字符串，并将结果转换为大写形式 返回结果*/
        return hs.toString().toUpperCase();
    }

    /*将十六进制字符串转换为字节数组*/
    public static String hex2bytes(String strHex) {
        if (null == strHex) {
            return null;
        }
        /*获取输入十六进制字符串的长度，命名为 strHexLen*/
        int strHexLen = strHex.length();
        /*如果输入十六进制字符串的长度是奇数，即 strHexLen % 2 == 1，则表示输入的字符串长度不符合要求，返回 null*/
        if (strHexLen % 2 == 1) {
            return null;
        }
        /*根据输入十六进制字符串的长度，计算出字节数组的长度，即 strHexLen / 2*/
        byte[] bytes = new byte[strHexLen / 2];

        for (int i = 0; i < bytes.length; i++) {
            /*
            从输入十六进制字符串中每两个字符解析为一个字节，
            并存储在字节数组中。具体实现是使用 Integer.parseInt() 方法将两个字符解析为一个整数，
            然后将整数强制转换为字节类型
             */
            bytes[i] = (byte) Integer.parseInt(strHex.substring(i * 2, i * 2 + 2));
        }
        /*返回字节数组的字符串表示，使用 Arrays.toString() 方法将字节数组转换为字符串*/
        return Arrays.toString(bytes);
    }

    /**
     * @Description  16进制直接转换成为字符串
     * @Date 15:42 2022/9/5
     * @Param [hex] 16进制字符串(Byte之间无分隔符
     * @return 解析出来的字符串
     **/
    public static String hexStr2Str(String hex) {
        StringBuilder hexStr = new StringBuilder();
        String str = "0123456789ABCDEF"; //16进制能用到的所有字符 0-15
        for(int i=0;i<hex.length();i++){
            String s = hex.substring(i, i+1);
            if(s.equals("a")||s.equals("b")||s.equals("c")||s.equals("d")||s.equals("e")||s.equals("f")){
                s=s.toUpperCase().substring(0, 1);
            }
            hexStr.append(s);
        }

        char[] hexs = hexStr.toString().toCharArray();//toCharArray() 方法将字符串转换为字符数组。
        int length = (hexStr.length() / 2);//1个byte数值 -> 两个16进制字符
        byte[] bytes = new byte[length];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            int position = i * 2;//两个16进制字符 -> 1个byte数值
            n = str.indexOf(hexs[position]) * 16;
            n += str.indexOf(hexs[position + 1]);
            // 保持二进制补码的一致性 因为byte类型字符是8bit的  而int为32bit 会自动补齐高位1  所以与上0xFF之后可以保持高位一致性
            //当byte要转化为int的时候，高的24位必然会补1，这样，其二进制补码其实已经不一致了，&0xff可以将高的24位置为0，低8位保持原样，这样做的目的就是为了保证二进制数据的一致性。
            bytes[i] = (byte) (n & 0xff);
        }
        String content = "";
        try {
            content = new String(bytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return content;
    }

}
